<?php

namespace CuiFox\yii\helpers;

use Yii;
use yii\helpers\ArrayHelper;
use yii\web\Response;
use yii\swiftmailer\Mailer;

class Tool
{
    /**
     * 验证选中
     * @param null $haystack
     * @param string $needle
     * @param int $attribute
     * @param string $delimiter
     * @return string
     */
    public static function checked($haystack = null, $needle = '', $attribute = 0, $delimiter = ',')
    {
        if ($attribute == 0) {
            $label = "selected";
        } else {
            $label = "checked";
        }

        $array = is_array($haystack) ? $haystack : explode($delimiter, (string)$haystack);
        if (in_array($needle, $array)) {
            return $label;
        }

        return '';
    }

    /**
     * 随机字符串
     * @param int $maxSize
     * @return string
     */
    public static function randString(int $maxSize = 6)
    {
        $code = '';
        $string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        for ($i = 1; $i <= $maxSize; $i++) {
            $rnd = rand(0, strlen($string) - 1);
            $code .= $string[$rnd];
        }
        return $code;
    }

    /**
     * 随机数字
     * @param int $length
     * @return int
     */
    public static function randNumber(int $length = 6)
    {
        // 确保生成的数字长度不小于 1
        $length = max(1, $length);

        // 计算最小值和最大值
        $min = pow(10, $length - 1);
        $max = pow(10, $length) - 1;

        return rand($min, $max);
    }

    /**
     * 请求
     * @param null $name
     * @param null $default
     * @return array|null|string
     */
    public static function input($name = null, $default = null)
    {
        $request = Yii::$app->request;
        $result = array_merge($request->post(), $request->get());
        if (isset($name)) {
            return $result[$name] ?? $default;
        }
        return $result;
    }

    /**
     * "*"替换字符串
     * @param string $string
     * @param int $start
     * @param int $length
     * @return array|string|string[]
     */
    public static function stringStar(string $string = '', int $start = 0, int $length = 0)
    {
        return substr_replace($string, str_repeat('*', $length), $start, $length);
    }

    /**
     * 过滤HTML标签
     * @param string $subject
     * @return string
     */
    public static function filterHtml(string $subject)
    {
        return empty($subject) ? '' : strip_tags(str_replace("&nbsp;", "", $subject));
    }

    /**
     * 判断是否为整数
     * @param $value
     * @param int $default
     * @return int
     */
    public static function isInt($value, int $default = 0): int
    {
        if ((string)$value === '' || !preg_match('/^-?\d+$/', $value)) {
            return $default;
        }
        return intval($value);
    }

    /**
     * 判断是否为数字
     * @param $value
     * @param $default
     * @return float|int|mixed|string
     */
    public static function isNumber($value, $default = 0)
    {
        return is_numeric($value) ? $value : $default;
    }

    /**
     * 验证手机格式
     * @param string $value
     * @return bool
     */
    public static function isPhone(string $value)
    {
        return preg_match('/^1[0-9]{10}$/', $value) && strlen($value) == 11;
    }

    /**
     * 验证邮箱
     * @param string $value
     * @return bool
     */
    public static function isEmail(string $value)
    {
        return filter_var($value, FILTER_VALIDATE_EMAIL);
    }

    /**
     * 获取树状结构
     * @param array $data
     * @param int $parentId
     * @param string $primaryKey
     * @param string $parentKey
     * @param string $childKey
     * @return array
     */
    public static function getTree(
        array $data = [],
        int $parentId = 0,
        string $primaryKey = 'id',
        string $parentKey = 'parent_id',
        string $childKey = 'children'
    ) {
        $tree = [];
        $data = array_column($data, null, $primaryKey);
        foreach ($data as $key => $it) {
            if ($it[$parentKey] == $parentId) {
                $tree[] = &$data[$key];
            } else {
                $data[$it[$parentKey]][$childKey][] = &$data[$key];
            }
        }
        return $tree;
    }

    /**
     * 递归获取root
     * @param $list
     * @param $id
     * @return mixed
     */
    public static function rootRecursion($list, $id)
    {
        foreach ($list as $it) {
            if ($it['id'] == $id) {
                if ($it['parent_id']) {
                    return self::rootRecursion($list, $it['parent_id']);
                } else {
                    return $it;
                }
            }
        }
    }

    /**
     * @param array $response
     * @return array
     */
    public static function response(array $response = [])
    {
        $response['success'] = $response['success'] ?? false;
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $response;
    }

    /**
     * @param $data
     * @param string $message
     * @return array
     */
    public static function success($data = null, string $message = '')
    {
        $response = [
            'success' => true,
            'message' => $message ?: Yii::t('app', 'success'),
        ];

        if ($data) {
            $response['data'] = $data;
        }

        return self::response($response);
    }

    /**
     * @param string $message
     * @param int $code
     * @param $data
     * @return array
     */
    public static function failure(string $message = '', int $code = 0, $data = null)
    {
        $response = [
            'success' => false,
            'code' => $code,
            'message' => $message ?: Yii::t('app', 'failure'),
        ];

        if ($data) {
            $response['data'] = $data;
        }

        return self::response($response);
    }

    /**
     * 获取Ip
     * @return array|false|string
     */
    public static function getClientIp()
    {
        $ip = false;
        if (isset($_SERVER["HTTP_CLIENT_IP"]) && $_SERVER["HTTP_CLIENT_IP"]) {
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']) {
            $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
        } elseif (isset($_SERVER["HTTP_WL_PROXY_CLIENT_IP"]) && $_SERVER["HTTP_WL_PROXY_CLIENT_IP"]) {
            $ip = $_SERVER["HTTP_WL_PROXY_CLIENT_IP"];
        } elseif (isset($_SERVER["HTTP_X_TRUE_IP"]) && $_SERVER["HTTP_X_TRUE_IP"]) {
            $ip = $_SERVER["HTTP_X_TRUE_IP"];
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR']) {
            $ip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv('REMOTE_ADDR')) {
            $ip = getenv('REMOTE_ADDR');
        }
        return $ip;
    }

    /**
     * @return string
     */
    public static function uniqueId()
    {
        return md5(uniqid(microtime() . mt_rand() . getmypid(), true));
    }

    /**
     * @return string
     */
    public static function uuid()
    {
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(self::uniqueId(), 4));
    }

    /**
     * @param string $url
     * @return array
     */
    public static function parseUrl(string $url = '')
    {
        $info = parse_url($url);
        $scheme = $info['scheme'] ?? '';
        $host = $info['host'] ?? '';
        $path = $info['path'] ?? '';
        $query = $info['query'] ?? '';

        return [
            'baseUrl' => $scheme . '://' . $host . $path,
            'query' => self::convertUrlQuery($query),
        ];
    }

    /**
     * Returns the url query as associative array
     * @param $query
     * @return array
     */
    public static function convertUrlQuery($query)
    {
        if (empty($query)) {
            return [];
        }

        $queryParts = explode('&', html_entity_decode($query, ENT_QUOTES, 'utf-8'));

        $params = [];
        foreach ($queryParts as $param) {
            $item = explode('=', $param);
            $params[$item[0]] = $item[1] ?? '';
        }

        return $params;
    }

    /**
     * @param $array_query
     * @return string
     */
    public static function getUrlQuery($array_query)
    {
        $tmp = [];
        foreach ($array_query as $k => $param) {
            $tmp[] = $k . '=' . $param;
        }
        return implode('&', $tmp);
    }

    /**
     * @param $string
     * @param int $length
     * @param string $spacer
     * @return string
     */
    public static function stringSpacer($string, int $length = 3, string $spacer = ' ')
    {
        $result = [];
        if ($length > 0) {
            $len = mb_strlen($string, "UTF-8");
            for ($i = 0; $i < $len; $i += $length) {
                $result[] = mb_substr($string, $i, $length, "UTF-8");
            }
        } else {
            $result = preg_split("//u", $length, -1, PREG_SPLIT_NO_EMPTY);
        }

        return implode($spacer, $result);
    }

    /**
     * 判断是否为移动端
     * @return bool
     */
    public static function isMobile()
    {
        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
            return true;
        }

        //此条摘自TPM智能切换模板引擎，适合TPM开发
        if (isset($_SERVER['HTTP_CLIENT']) && 'PhoneClient' == $_SERVER['HTTP_CLIENT']) {
            return true;
        }

        //如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        //找不到为false,否则为true
        if (isset($_SERVER['HTTP_VIA'])) {
            return (bool)stristr($_SERVER['HTTP_VIA'], 'wap');
        }

        //判断手机发送的客户端标志,兼容性有待提高
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
            $keywords = [
                'nokia',
                'sony',
                'ericsson',
                'mot',
                'samsung',
                'htc',
                'sgh',
                'lg',
                'sharp',
                'sie-',
                'philips',
                'panasonic',
                'alcatel',
                'lenovo',
                'iphone',
                'ipod',
                'blackberry',
                'meizu',
                'android',
                'netfront',
                'symbian',
                'ucweb',
                'windowsce',
                'palm',
                'operamini',
                'operamobi',
                'openwave',
                'nexusone',
                'cldc',
                'midp',
                'wap',
                'mobile',
            ];
            //从HTTP_USER_AGENT中查找手机浏览器的关键字
            if (preg_match("/(" . implode('|', $keywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
                return true;
            }
        }
        //协议法，因为有可能不准确，放到最后判断
        if (isset($_SERVER['HTTP_ACCEPT'])) {
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'],
                        'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'],
                            'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 创建url
     * @param array $params
     * @return string
     */
    public static function createUrl(array $params = [])
    {
        if (empty($params)) {
            return '';
        }
        ksort($params);
        $string = '';
        foreach ($params as $k => $val) {
            $string .= $k . '=' . $val . '&';
        }
        return rtrim($string, '&');
    }

    /**
     * URL base64解码
     * '-' -> '+'
     * '_' -> '/'
     * 字符串长度%4的余数，补'='
     * @param $string
     * @return bool|string
     */
    public static function urlSafeBase64Decode($string)
    {
        $data = str_replace(['-', '_'], ['+', '/'], $string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    /**
     * URL base64编码
     * @param $string
     * @return array|string|string[]
     */
    public static function urlSafeBase64Encode($string)
    {
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($string));
    }

    /**
     * echo csrf input form
     * @return string
     */
    public static function inputCSRF()
    {
        $reqeust = Yii::$app->getRequest();
        return '<input type="hidden" name="' . $reqeust->csrfParam . '" value="' . $reqeust->getCsrfToken() . '"/>';
    }

    /**
     * 上传
     * @param array $options
     * @return string
     */
    public static function copper(array $options = [])
    {
        $acceptMime = [
            'images' => 'image/*',
        ];

        $default = [
            'name' => '',
            'title' => '上传',
            'accept' => 'images',
            'multiple' => false,
            'value' => '',
        ];

        $options = array_merge($default, $options);
        $options['id'] = md5($options['name']);
        $options['elem'] = '#button-' . $options['id'];
        $options['acceptMime'] = $acceptMime[$options['accept'] ?? ''] ?? '*';

        return '<input type="hidden" name="' . $options['name'] . '"/>
                <button type="button" class="layui-btn layui-btn-normal" id="button-' . $options['id'] . '">' . $options['title'] . '</button>
                <div class="layui-upload-list list-' . $options['accept'] . '" id="upload-list-' . $options['id'] . '"></div>
                <script>$(function(){copper(' . json_encode($options) . ')})</script>';
    }

    /**
     * 上传
     * @param array $options
     * @return string
     */
    public static function upload(array $options = [])
    {
        $acceptMime = [
            'images' => 'image/*',
        ];

        $default = [
            'name' => '',
            'title' => '上传',
            'accept' => 'images',//images（图片）、file（所有文件）、video（视频）、audio（音频）
            'multiple' => false,
            'value' => '',
        ];

        $options = array_merge($default, $options);
        $options['id'] = md5($options['name']);
        $options['elem'] = '#button-' . $options['id'];
        $options['acceptMime'] = $acceptMime[$options['accept'] ?? ''] ?? '*';

        $html = '<input type="hidden" name="' . $options['name'] . '"/>
                <button type="button" class="layui-btn layui-btn-normal" id="button-' . $options['id'] . '">' . $options['title'] . '</button>
                <div class="layui-upload-list list-' . $options['accept'] . '" id="upload-list-' . $options['id'] . '"></div>
                <script>$(function(){uploads(' . json_encode($options) . ')})</script>';
        return $html;
    }

    /**
     * 导入
     * @param array $options
     * @param null $append
     * @return string
     */
    public static function excel(array $options = [], $append = null)
    {
        $default = [
            'name' => '',
            'title' => '导入',
            'accept' => 'file',
            'exts' => 'xls|xlsx',
            'multiple' => false,
            'data' => [],
        ];

        $options = array_merge($default, $options);
        $options['id'] = md5($options['name']);
        $options['elem'] = '#button-' . $options['id'];

        if (is_array($append)) {
            $append = implode('', $append);
        }

        return '<input type="hidden" name="' . $options['name'] . '"/>
                <button type="button" class="layui-btn layui-btn-normal" id="button-' . $options['id'] . '">' . $options['title'] . '</button>
                ' . $append . '
                <div class="layui-excel-list list-' . $options['accept'] . '" id="upload-list-' . $options['id'] . '">
                <table class="layui-table" id="list" lay-filter="list"></table>
                <script type="text/html" id="toolbar-left">
                    <div class="layui-btn-container">
                        <button class="layui-btn layui-btn-sm" lay-event="delete">删除</button>
                    </div>
                </script>
                <script type="text/html" id="toolbar-right">
                    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">删除</a>
                </script>
                </div>
                <script>$(function(){excel(' . json_encode($options) . ')})</script>';
    }

    /**
     * @param $string
     * @param $length
     * @return string
     */
    public static function subString($string, $length)
    {
        // 过滤 HTML 标签
        $string = self::filterHtml($string);

        // 获取字符串的实际长度（支持多字节字符）
        $strLength = mb_strlen($string, 'UTF-8');

        // 如果字符串长度小于或等于指定长度，直接返回原字符串
        if ($strLength <= $length) {
            return $string;
        }

        // 截取字符串并添加后缀
        return mb_substr($string, 0, $length, 'UTF-8') . '...';
    }

    /**
     * @param array $param
     * [
     *  'to' => '收件人',
     *  'subject' => '主题',
     *  'body' => '内容',
     *  'view' => '模板',
     *  'data' => [], //模板数据
     * ]
     * @param array $config
     * @return int
     * @throws \yii\base\InvalidConfigException
     */
    public static function mail($param, array $config = [])
    {
        $mailer = new Mailer();
        $transport = [
            'class' => 'Swift_SmtpTransport',
            'host' => $config['host'],
            'username' => $config['username'],
            'password' => $config['password'],
            'port' => $config['port'] ?? 25,
            'encryption' => $config['encryption'] ?? 'ssl',
        ];

        $mailer->messageConfig = [
            'charset' => 'UTF-8',
            'from' => [$config['from_address'] => $config['from_name']],
        ];
        $mailer->setTransport($transport);

        $messages = [];
        foreach ((array)$param['to'] as $it) {
            if (!isset($param['view'])) {
                $messages[] = $mailer->compose()->setTo($it)->setSubject($param['subject'])->setHtmlBody($param['body']);
                //->setTextBody($param['body']);
            } else {
                //加载模板
                $messages[] = $mailer->compose($param['view'],
                    $param['data'])->setTo($it)->setSubject($param['subject']);
            }
        }

        return $mailer->sendMultiple($messages);
    }

    /**
     * 获取协议
     * @return string
     */
    public static function getProtocol()
    {
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https" : "http";
        if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
            $protocol = 'https';
        }
        return $protocol;
    }

    /**
     * 获取Host Url
     * @return string
     */
    public static function getHostUrl()
    {
        return self::getProtocol() . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * @param int $second
     * @return array
     */
    public static function timeDiff(int $second = 0)
    {
        return [
            'day' => floor($second / 3600 / 24),
            'hour' => floor(($second % (3600 * 24)) / 3600),
            'minute' => floor(($second % (3600 * 24)) % 3600 / 60),
            'second' => floor(($second % (3600 * 24)) % 60),
        ];
    }

    /**
     * 数字转汉字
     * @param $num
     * @return string
     */
    public static function numberToChinese($num)
    {
        $chiNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
        $chiUni = ['', '十', '百', '千', '万', '十', '百', '千', '亿'];
        $num_str = (string)$num;
        $count = strlen($num_str);
        $last_flag = true; //上一个 是否为0
        $zero_flag = true; //是否第一个
        $temp_num = null; //临时数字
        $chiStr = '';//拼接结果
        if ($count == 2) {//两位数
            $temp_num = $num_str[0];
            $chiStr = $temp_num == 1 ? $chiUni[1] : $chiNum[$temp_num] . $chiUni[1];
            $temp_num = $num_str[1];
            $chiStr .= $temp_num == 0 ? '' : $chiNum[$temp_num];
        } else {
            if ($count > 2) {
                $index = 0;
                for ($i = $count - 1; $i >= 0; $i--) {
                    $temp_num = $num_str[$i];
                    if ($temp_num == 0) {
                        if (!$zero_flag && !$last_flag) {
                            $chiStr = $chiNum[$temp_num] . $chiStr;
                            $last_flag = true;
                        }

                        if ($index == 4 && $temp_num == 0) {
                            $chiStr = "万" . $chiStr;
                        }
                    } else {
                        if ($i == 0 && $temp_num == 1 && $index == 1 && $index == 5) {
                            $chiStr = $chiUni[$index % 9] . $chiStr;
                        } else {
                            $chiStr = $chiNum[$temp_num] . $chiUni[$index % 9] . $chiStr;
                        }
                        $zero_flag = false;
                        $last_flag = false;
                    }
                    $index++;
                }
            } else {
                $chiStr = $chiNum[$num_str[0]];
            }
        }
        return $chiStr;
    }

    /**
     * 获取Referer
     * @return mixed
     */
    public static function getReferrer()
    {
        $referrer = self::input('referrer');
        if (!$referrer) {
            $referrer = Yii::$app->request->referrer;
        }
        return $referrer;
    }

    /**
     * 控制台获取当前环境
     * @return mixed|string
     */
    public static function env($env = 'local', $option = '--app-env=')
    {
        $args = $_SERVER['argv'];
        foreach ($args as $key => $arg) {
            if (strpos($arg, $option) === 0) {
                $env = substr($arg, strlen($option));
                // 移除自定义参数，避免干扰后续命令
                unset($args[$key]);
            }
        }
        // 重新设置命令行参数（移除 $option 后）
        $_SERVER['argv'] = array_values($args);
        $_SERVER['argc'] = count($_SERVER['argv']);
        return $env;
    }

    /**
     * @param $name
     * @param $default
     * @return mixed
     * @throws \Exception
     */
    public static function param($name, $default = null)
    {
        return ArrayHelper::getValue(Yii::$app->params, $name, $default);
    }
}